#include <archive.h>
#include <archive_entry.h>
#include <getopt.h>
#include <sys/types.h>
#include <md5.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <fetch.h>
#include <regex.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/* Libpkg base. */
#include <pkg.h>
/* FreeBSD package and database. */
#include <pkg_freebsd.h>

#if 0
/* FreeBSD routines. */
#include <pkg_install.h>
#endif

typedef enum {
        MATCH_ALL,
        MATCH_EXACT,
        MATCH_EREGEX,
        MATCH_GLOB,
        MATCH_NGLOB,
        MATCH_REGEX
} match_t;

typedef enum {
        REMOTE_REPOSITORY,
        LOCAL_REPOSITORY,
        URL,
        LOCAL,
        WHICH,
        INSTALLED
} target_t;

struct pkg_target {
        char target[PATH_MAX];
        target_t target_type;
        STAILQ_ENTRY(pkg_target) next;
};

struct info_config {
        STAILQ_HEAD(target_head, pkg_target) targets;
        STAILQ_HEAD(which_head, pkg_target) which;
        const char *database_location;
        const char *info_prefix;
        int verbose;
        int quiet;
        int show_flags;
        /* related... */
        int skip_flags;
        match_t match;
        int use_block_size;
        const char *check_package;
        const char *lookup_origin;
        int keep_package;
};

#define FLAGGED(x, y) (x & y)
#define SET_FLAG(x, y) (x |= y)

#define PKG_INFO_VERSION 00000000

#define SHOW_LIBPKG_VERSION 0x00000001
#define SHOW_PKG_INFO_VERSION 0x00000002
#define SHOW_PKG_NAME 0x00000004
#define SHOW_COMMENT 0x00000008
#define SHOW_DESCRIPTION 0x00000010
#define SHOW_DEINSTALL 0x00000020
#define SHOW_DISPLAY 0x00000040
#define SHOW_INSTALL 0x00000080
#define SHOW_MTREE 0x00000100
#define SHOW_PLIST 0x00000200
#define SHOW_INDEX 0x00000400
#define XXXXXXXXXX 0x00000800
#define SHOW_CHECKSUM_CHECK 0x00001000
#define SHOW_REQUIRE 0x00010000
#define SHOW_DEPEND 0x00020000
#define SHOW_SIZE 0x00040000
#define SHOW_ORIGIN 0x00080000
#define SHOW_PKGNAME 0x00100000
#define SHOW_FILES 0x00200000
#define SHOW_REQBY 0x00400000
#define SHOW_FMTREV 0x00800000
#define SHOW_PREFIX 0x01000000
#define SHOW_CONFLICTS 0x02000000
#define SHOW_OPTIONS 0x04000000

#define PKG_DBDIR "/var/db/pkg";

#define SKIP_ALL FBSD_METACODE_COMMENT | FBSD_METACODE_CONTENTS

static void clean_up(int);
static void parse_arguments(int, char **);
static void usage(void);
static void version(void);
static int is_url(const char *);
static int regex_match(const char *, const char *, int);
static int glob_match(const char *, const char *);
static int info_show(struct pkg *p, struct info_config *);
static void config_init(struct info_config *);
static int pkg_info(struct info_config *);
static int pattern_match(match_t, const char *, const char *);
static int pkg_info_hash_match(struct pkg_file *);
static void print_chunk(struct pkg *, const char *(*)(struct pkg *), 
        const char *, struct info_config *);
static void print_file(const char *, const char *, struct info_config *);

/* Configuration for pkg_info run. */
struct info_config c;

static int
is_url(const char *path)
{
        (void)path;
        return (0);
}

static void
parse_arguments(int argc, char **argv)
{
        struct pkg_target *pt;
        int o;

        static char opts[] = "abcdDe:EfgGhiIjkKl:LmoO:pPqQrRst:vVW:xX";
        static struct option long_opts[] = {
                { "all",	no_argument,		NULL,		'a' },
                { "blocksize",	no_argument,		NULL,		'b' },
                { "exist",	required_argument,	NULL,		'X' },
                { "exists",	required_argument,	NULL,		'X' },
                { "extended",	no_argument,		NULL,		'e' },
                { "help",	no_argument,		NULL,		'h' },
                { "keep",	no_argument,		NULL,		'K' },
                { "no-glob",	no_argument,		NULL,		'G' },
                { "origin",	required_argument,	NULL,		'O' },
                { "quiet",	no_argument,		NULL,		'q' },
                { "regex",	no_argument,		NULL,		'x' },
                { "template",	required_argument,	NULL,		't' },
                { "verbose",	no_argument,		NULL,		'v' },
                { "version",	no_argument,		NULL,		'P' },
                { "which",	required_argument,	NULL,		'W' },
                { NULL,		0,			NULL,		0 }
        };
        
        if (argc == 1) {
                /* No args.  Set up a basic name/comment dump. */
                c.match = MATCH_ALL;
                c.show_flags = SHOW_INDEX;
                return;
        }

        /* Go through command line arguments and set up our config. */
        while ((o = getopt_long(argc, argv, opts, long_opts, NULL)) != -1) {
                switch (o) {
                case 'a':
                        c.match = MATCH_ALL;
                        break;
                case 'b':
                        c.use_block_size = 1;
                        break;
                case 'c':
                        c.show_flags |= SHOW_COMMENT;
                        break;
                case 'd':
                        c.show_flags |= SHOW_DESCRIPTION;
                        break;
                case 'e':
                        c.check_package = optarg;
                        break;
                case 'f':
                        c.show_flags |= SHOW_PLIST;
                        c.show_flags |= SHOW_FILES;
                        // c.show_flags |= SHOW_SRCDIR;
                        // c.show_flags |= SHOW_INSTALL;
                        // c.show_flags |= SHOW_DEINSTALL;
                        // c.show_flags |= SHOW_COMMENT;
                        c.show_flags |= SHOW_PKG_NAME;
                        // c.show_flags |= SHOW_DISPLAY;
                        c.show_flags |= SHOW_DEPEND;
                        // c.show_flags |= SHOW_CONFLICTS;
                        // c.show_flags |= SHOW_DIRRM;
                        c.show_flags |= SHOW_ORIGIN;
                        c.show_flags |= SHOW_OPTIONS;
                        c.show_flags |= SHOW_FMTREV;
                        break;
                case 'g':
                        c.show_flags |= SHOW_CHECKSUM_CHECK;
                        break;
                case 'i':
                        c.show_flags |= SHOW_INSTALL;
                        break;
                case 'j':
                        c.show_flags |= SHOW_REQUIRE;
                        break;
                case 'k':
                        c.show_flags |= SHOW_DEINSTALL;
                        break;
                case 'l':
                        c.info_prefix = optarg;
                        break;
                case 'r':
                        c.show_flags |= SHOW_DEPEND;
                        break;
                case 'm':
                        c.show_flags |= SHOW_MTREE;
                        break;
                case 's':
                        c.show_flags |= SHOW_SIZE;
                        break;
                case 'o':
                        c.show_flags |= SHOW_ORIGIN;
                        break;
                case 'q':
                        c.quiet = 1;
                        break;
                case 'v':
                        c.verbose = 1;
                        c.show_flags |= SHOW_COMMENT | SHOW_DESCRIPTION |
                                SHOW_PLIST | SHOW_INSTALL |
                                SHOW_DEINSTALL | SHOW_REQUIRE | SHOW_DISPLAY |
                                SHOW_MTREE;
                case 'x':
                        c.match = MATCH_REGEX;
                        break;
                case 'D':
                        c.show_flags |= SHOW_DISPLAY;
                        break;
                case 'E':
                        c.show_flags |= SHOW_PKGNAME;
                        break;
                case 'G':
                        c.match = MATCH_EXACT;
                        break;
                case 'I':
                        c.show_flags |= SHOW_INDEX;
                        break;
                case 'K':
                        c.keep_package = 1;
                        break;
                case 'L':
                        c.show_flags |= SHOW_FILES;
                        break;
                case 'O':
                        c.lookup_origin = optarg;
                        break;
                case 'P':
                        c.show_flags |= SHOW_PKG_INFO_VERSION;
                        c.show_flags |= SHOW_LIBPKG_VERSION;
                        break;
                case 'Q':
                        c.quiet = 1;
                        break;
                case 'R':
                        c.show_flags |= SHOW_REQBY;
                        break;
                case 'V':
                        c.show_flags |= SHOW_FMTREV;
                        break;
                case 'X':
                        c.match = MATCH_EREGEX;
                        break;
                case 'W':
                        pt = calloc(1, sizeof(*pt));
                        if (pt == NULL) {
                                warnx("Allocation error.");
                                clean_up(1);
                        }
                        strcpy(pt->target, optarg);
                        STAILQ_INSERT_TAIL(&c.which, pt, next);
                        break;
                /* OUT OF ORDER */
                case 'h':
                /* FALLTHROUGH */
                default:
                        usage();
                }
        }

        if (c.show_flags == 0) {
                c.show_flags = SHOW_COMMENT | SHOW_DESCRIPTION | SHOW_REQBY;
        }
        
        /* If I put this in a for loop it wont compile with -Werror. */
        argv += optind;
        for (; *argv != NULL; ++argv) {
                pt = calloc(1, sizeof(*pt));
                strcpy(pt->target, *argv);
                STAILQ_INSERT_TAIL(&c.targets, pt, next);
        }
}

static void
usage(void)
{
        fprintf(stderr, "Usage place holder\n");
        clean_up(1);
}

static void
version(void)
{
        printf("pkg_info %d - libpkg %d\n", PKG_INFO_VERSION, LIBPKG_VERSION);
}

static void
config_init(struct info_config *_c)
{
        STAILQ_INIT(&_c->targets);
        STAILQ_INIT(&_c->which);

        _c->database_location = getenv("PKG_DBDIR");
        if (_c->database_location == NULL) {
                _c->database_location = PKG_DBDIR;
        }

        _c->info_prefix = "";
        _c->check_package = NULL;
        _c->lookup_origin = NULL;
        
        _c->verbose = 0;
        _c->quiet = 0;
        _c->show_flags = 0;
        /* related... */
        _c->skip_flags = 0;
        _c->use_block_size = 0;
        
        _c->match = -1;
}

int
main(int argc, char **argv)
{
        int r;
        
        /* Init these so clean_up() knows what's up. */
        config_init(&c);

        signal(SIGINT, clean_up);

        parse_arguments(argc, argv);
        
        if (FLAGGED(c.show_flags, SHOW_PKG_INFO_VERSION)) {
                version();
                clean_up(0);
        }
        
        r = pkg_info(&c);
        clean_up(r);
        
        /* NOT REACHED */
        return (0);
}

static int
pkg_info(struct info_config *_c)
{
        /* XXX: This can be re-written. */
        int r;
        int s;
        unsigned int match_count;
        struct pkg_target *pt;
        struct pkg_file f;
        FILE *pkg_fp;
        (void)pkg_fp;
        char *target;
        struct stat sb;
        const char *pathname;
        char path[PATH_MAX];
        struct pkg_database *db;
        struct pkg *p;
        
        db = pkg_freebsd_database_create();
        p = pkg_freebsd_create();
        s = pkg_database_open(db, _c->database_location, 0);
        if (s != PKG_OK) {
                warnx("Error opening database");
                pkg_database_release(db);
                pkg_release(p);
                return (1);
        }

        r = 0;
        if (FLAGGED(_c->show_flags, SHOW_PKGNAME)) {
                while (pkg_database_get_next_pkg(db, p, _c->skip_flags) ==
                        PKG_OK) {
                        if (!_c->quiet) {
                                printf("%s", _c->info_prefix);
                        }
                        printf("%s\n", pkg_freebsd_get_name(p));
                }
        } else if (_c->check_package != NULL) {
                while (pkg_database_get_next_pkg(db, p, _c->skip_flags) ==
                        PKG_OK) {
                        if (strcmp(_c->check_package, 
                                pkg_freebsd_get_name(p)) == 0) {
                                /* Get out. */
                                pkg_database_close(db);
                                pkg_database_release(db);
                                pkg_release(p);
                                return (0);
                        }
                }
                r = 1;
        } else if (!STAILQ_EMPTY(&_c->which)) {
                /* Clean up the targets. */
                STAILQ_FOREACH(pt, &_c->which, next) {
                        if (stat(pt->target, &sb) < 0) {
                                target = pkg_exec_run("/usr/bin/which %s",
                                        pt->target);
                                if (target != NULL) {
                                        warnx("Can't find %s\n", pt->target);
                                } else {
                                        strcpy(pt->target, target);
                                }
                        }
                }
                pkg_database_rewind(db);
                while (pkg_database_get_next_pkg(db, p, _c->skip_flags) == 
                        PKG_OK) {
                        while (pkg_freebsd_get_next_file(p, &f) == PKG_OK) {
                                pathname = pkg_freebsd_file_get_pathname(&f);
                                strcpy(path, pkg_freebsd_file_get_prefix(&f));
                                strcat(path, "/");
                                strcat(path, pathname);
                                STAILQ_FOREACH(pt, &_c->which, next) {
                                        if (strcmp(path, pt->target) == 0) {
                                                printf("%s was installed by "
                                                "package %s\n", pt->target,
                                                pkg_freebsd_get_name(p));
                                        }
                                }
                        }
                }
        } else if (_c->lookup_origin != NULL) {
                if (!_c->quiet) {
                        printf("The following installed package(s) has %s "
                        "origin:\n", _c->lookup_origin);
                }
                while (pkg_database_get_next_pkg(db, p, _c->skip_flags) == 
                        PKG_OK) {
                        if (strcmp(_c->lookup_origin, 
                                pkg_freebsd_get_origin(p)) == 0) {
                                printf("%s\n", pkg_freebsd_get_name(p));
                        }
                }
        } else {
                match_count = 0;
                while (pkg_database_get_next_pkg(db, p, _c->skip_flags) ==
                        PKG_OK) {
                        if (_c->match == MATCH_ALL) {
                                info_show(p, _c);
                                match_count++;
                        } else {
                                STAILQ_FOREACH(pt, &_c->targets, next) {
                                        if (pattern_match(_c->match,
                                                pkg_freebsd_get_name(p),
                                                pt->target)) {
                                                info_show(p, _c);
                                                match_count++;
                                        }
                                }
                        }
                }
                if (match_count == 0) {
                /* We had no matches.  Current pkg_info says we should complain.
                 * */
                        switch (_c->match) {
                        case (MATCH_GLOB):
                        case (MATCH_NGLOB):
                                break;
                        case (MATCH_ALL):
                                warnx("no packages installed");
                                break;
                        case (MATCH_REGEX):
                        case (MATCH_EREGEX):
                                warnx("no packages match pattern(s)");
                                r = 1;
                                break;
                        default:
                                break;
                        }
                }
        }
        
        pkg_database_close(db);
        pkg_database_release(db);
        pkg_release(p);
        return (r);
}

static int
regex_match(const char *string, const char *pattern, int extended)
{
        int r;
        int be;
        regex_t re;
        
        be = (extended ? REG_EXTENDED : REG_BASIC);
        r = regcomp(&re, pattern, be | REG_NOSUB);
        if (r == 0) {
                r = regexec(&re, string, (size_t)0, NULL, 0);
                regfree(&re);
        }

        if (r == 0) {
                return (1);
        } else if (r != REG_NOMATCH) {
                /* XXX: Should print an error. */
                return (0);
        }

        return (0);
}

static int
glob_match(const char *string, const char *pattern)
{
        (void)string;
        (void)pattern;
        return (1);
}

static int
pattern_match(match_t match, const char *string, const char *pattern)
{
        /* XXX: I don't have version comparison in here yet. */

        switch (match) {
        case (MATCH_ALL):
                return (1);
        case (MATCH_NGLOB):
        case (MATCH_GLOB):
                return (glob_match(string, pattern));
        case (MATCH_EREGEX):
        case (MATCH_REGEX):
                return (regex_match(string, pattern, match == MATCH_EREGEX));
        default:
                break;
        }

        return (0);
}

/* Clears out the STAILQs in our config. */
static void
clean_up(int r)
{
        (void)is_url;
        /* XXX: Clear config tailq. */
        exit(r);
}

static int
info_show(struct pkg *_p, struct info_config *_c)
{
        /* TODO: Break this up into smaller functions to make it readable.  Too
         * many levels of indentation. */
        const char *show;
        const char *prefix;
        const char *last_prefix;
        
        struct pkg_conflict cn;
        struct pkg_dependency dp;
        struct pkg_file fl;
        
        if (FLAGGED(_c->show_flags, SHOW_INDEX)) {
                /* No newline because _data_read picks that up from the file. */
                printf("%-19s %s", pkg_freebsd_get_name(_p),
                        pkg_freebsd_get_comment(_p));
        } else {
                if (!_c->quiet) {
                        printf("%sInformation for %s:\n\n", _c->info_prefix,
                        pkg_freebsd_get_name(_p));
                } else {
                        printf("%s%s:", _c->info_prefix,
                        pkg_freebsd_get_name(_p));
                }
                if (FLAGGED(_c->show_flags, SHOW_PLIST)) {
                        /* TODO: Write a show plist function for this flag
                         * because the output is jacked in this case. */
                        if (!_c->quiet) {
                                printf("%sPacking list:\n", _c->info_prefix);
                        }
                }
                if (FLAGGED(_c->show_flags, SHOW_COMMENT)) {
                        print_chunk(_p, pkg_freebsd_get_comment, "Comment:\n",
                                _c);
                }
                if (FLAGGED(_c->show_flags, SHOW_CONFLICTS)) {
                        if (!_c->quiet) {
                                /* Eh, no title on this one... */
                        }
                        while (pkg_freebsd_get_next_conflict(_p, &cn) == 
                                PKG_OK) {
                                printf((_c->quiet ? "@conflicts: %s\n" : 
                                "Conflicts: %s\n"),
                                pkg_freebsd_conflict_get_expression(&cn));
                        }
                }
                if (FLAGGED(_c->show_flags, SHOW_DEPEND)) {
                        if (!_c->quiet) {
                                printf("%sDepends on:\n", _c->info_prefix);
                        }
                        while (pkg_freebsd_get_next_dependency(_p, &dp) ==
                                PKG_OK) {
                                show = pkg_freebsd_dependency_get_name(&dp);
                                printf((_c->quiet ? "@pkgdep: %s\n" : 
                                "Dependency: %s\n"), show);
                                show = pkg_freebsd_dependency_get_origin(&dp);
                                printf((_c->quiet ? "@comment DEPORIGIN:%s\n" :
                                "\tdependency origin: %s\n"), show);
                        }
                        /* Separator. */
                        printf("\n");
                }
                if (FLAGGED(_c->show_flags, SHOW_REQBY)) {
                        if (!_c->quiet) {
                                printf("%sRequired by:\n", _c->info_prefix);
                        }
                        while ((show = pkg_freebsd_get_next_required_by(_p)) !=
                                NULL) {
                                printf("%s\n", show);
                        }
                }
                if (FLAGGED(_c->show_flags, SHOW_DESCRIPTION)) {
                        print_chunk(_p, pkg_freebsd_get_description,
                                "Description\n", _c);
                }
                if (FLAGGED(_c->show_flags, SHOW_DISPLAY)) {
                        print_chunk(_p, pkg_freebsd_get_display, 
                        "Install notice:\n", _c);
                }
                if (FLAGGED(_c->show_flags, SHOW_REQUIRE)) {
#if 0
                        show = pkg_freebsd_get_require(_p);
                        if (show != NULL) {
                                printf("%sRequirements script:\n%s",
                                _c->info_prefix, show);
                        }
#endif
                }
                if (FLAGGED(_c->show_flags, SHOW_INSTALL)) {
                        show = pkg_freebsd_get_install_script_path(_p);
                        if (show != NULL) {
                                print_file(show, "Install script:\n", _c);
                        }
                        show = pkg_freebsd_get_post_install_script_path(_p);
                        if (show != NULL) {
                                print_file(show, "Post-install script:\n", _c);
                        }
                }
                if (FLAGGED(_c->show_flags, SHOW_DEINSTALL)) {
                        show = pkg_freebsd_get_deinstall_script_path(_p);
                        if (show != NULL) {
                                print_file(show, "Deinstall script:\n", _c);
                        }
                        show = pkg_freebsd_get_post_deinstall_script_path(_p);
                        if (show != NULL) {
                                print_file(show, "Post-deinstall script:\n", _c);
                        }
                }
                if (FLAGGED(_c->show_flags, SHOW_MTREE)) {
                }
                if (FLAGGED(_c->show_flags, SHOW_PREFIX)) {
                        /* XXX: I need to think about how to deal with this.
                         * For now, only dump prefix when using SHOW_FILE
                         * aswell. */
                }
                if (FLAGGED(_c->show_flags, SHOW_FILES)) {
                        /* Not the same as showing files for SHOW_PLIST.
                         * */
                        if (!_c->quiet) {
                                printf("%sFiles:\n", _c->info_prefix);
                        }
                        prefix = NULL;
                        last_prefix = NULL;
                        while (pkg_freebsd_get_next_file(_p, &fl) == PKG_OK) {
                                if (last_prefix == NULL) {
                                        last_prefix = 
                                        pkg_freebsd_file_get_prefix(&fl);
                                } else {
                                        /* Check the prefix to see if it's 
                                         * changed. */
                                        prefix =
                                        pkg_freebsd_file_get_prefix(&fl);
                                        if (strcmp(prefix, last_prefix) == 0) {
                                                last_prefix = prefix;
                                        }
                                }
                                if (!pkg_freebsd_file_get_ignored(&fl)) {
                                        printf("%s/%s\n", last_prefix,
                                        pkg_freebsd_file_get_pathname(&fl));
                                }
                        }
                }
                if (FLAGGED(_c->show_flags, SHOW_SIZE)) {
                }
                if (FLAGGED(_c->show_flags, SHOW_CHECKSUM_CHECK)) {
                        if (!_c->quiet) {
                                printf("%sMismatched Checksums:\n",
                                _c->info_prefix);
                        }
                        while (pkg_freebsd_get_next_file(_p, &fl) == PKG_OK) {
                                if (pkg_info_hash_match(&fl)) {
                                        if (!_c->verbose) {
                                                /* 
                                                 * This is gross, but I need
                                                 * some help with the 80 column
                                                 * barrier in this function :)
                                                 */
                                                continue;
                                        }
                                        printf("%s/%s matched the original MD5 "
                                        "checksum\n",
                                        pkg_freebsd_file_get_prefix(&fl),
                                        pkg_freebsd_file_get_pathname(&fl));
                                } else {
                                        printf("%s/%s fails the original MD5 "
                                        "checksum\n",
                                        pkg_freebsd_file_get_prefix(&fl),
                                        pkg_freebsd_file_get_pathname(&fl));
                                }
                        }
                }
                if (FLAGGED(_c->show_flags, SHOW_ORIGIN)) {
                        if (!_c->quiet) {
                                printf("%sOrigin:\n", _c->info_prefix);
                        }
                        printf("%s\n", pkg_freebsd_get_origin(_p));
                }
                if (FLAGGED(_c->show_flags, SHOW_FMTREV)) {
                        if (!_c->quiet) {
                                printf("%sFormat revision:\n", _c->info_prefix);
                        }
                        printf("%s\n", pkg_freebsd_get_format_revision(_p));
                }
        }
        
        /* A bit of seperation. */
        if (!FLAGGED(_c->show_flags, SHOW_INDEX)) {
                /* Adds an extra newline to SHOW_INDEX dumps. */
                printf("\n");
        }
        return (0);
}

static int
pkg_info_hash_match(struct pkg_file *f)
{
        char path[PATH_MAX];
        char hash[33];
        char *calc_hash;
        size_t link_len;
        char link_buf[PATH_MAX];
        struct stat sb;
        
        _pkg_util_path_join(path, pkg_freebsd_file_get_prefix(f),
                pkg_freebsd_file_get_pathname(f));
        if (lstat(path, &sb) < 0) {
                /* 
                 * Technically, we're better than the current pkg_info here.
                 * pkg_info reports that a file doesn't exist just because it
                 * can't open it.  That's a bug.
                 */
                warnx("%s does not exist", path);
                return (0);
        }

        /* 
         * We're not dealing with pre 1.1 properties.  Symlink 
         * hash for a symlink is on the string returned by
         * readlink(). 
         */
        calc_hash = NULL;
        if (S_ISLNK(sb.st_mode)) {
                link_len = readlink(path, link_buf, PATH_MAX);
                if (link_len > 0) {
                        calc_hash = MD5Data(link_buf, link_len, hash);
                }
        } else if (S_ISREG(sb.st_mode)) {
                calc_hash = MD5File(path, hash);
        }
        if (calc_hash != NULL) {
                if (strcmp(calc_hash, pkg_freebsd_file_get_hash(f)) != 0) {
                        return (0);
                } else {
                        return (1);
                }
        }

        return (0);
}

static void
print_chunk(struct pkg *p, const char *(*get_callback) (struct pkg *), 
        const char *title, struct info_config *_c)
{
        const char *chunk;

        if (!_c->quiet) {
                printf("%s%s", _c->info_prefix, title);
        }

        chunk = get_callback(p);
        if (chunk != NULL) {
                printf("%s", chunk);
        }
}

static void
print_file(const char *pathname, const char *title, struct info_config *_c)
{
        FILE *fp;
        char line[LINE_MAX];
        
        if (!_c->quiet) {
                printf("%s%s", _c->info_prefix, title);
        }

        fp = fopen(pathname, "r");
        if (fp == NULL) {
                warnx("Error: %s: Can't open '%s' for reading!\n", __func__,
                        pathname);
        }
        while (fgets(line, LINE_MAX, fp) != NULL) {
                printf("%s", line);
        }
        printf("\n");
}
